import os
import pandas as pd
from prophet import Prophet
from prophet.diagnostics import cross_validation, performance_metrics
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import redis
import json

# 配置Redis连接
redis_client = redis.StrictRedis(host='106.14.88.143', port=6379, db=0, password='redis')


def load_data(file_path):
    df = pd.read_excel(file_path, engine='openpyxl')
    df['时间'] = pd.to_datetime(df['时间'])
    return df.rename(columns={'时间': 'ds', '进出港次数': 'y'})


def train_model(df):
    model = Prophet(
        seasonality_mode='additive',
        seasonality_prior_scale=1.0,
        changepoint_prior_scale=0.5,
        n_changepoints=30,
        interval_width=0.65
    )
    model.fit(df)
    return model


def predict(model, periods=14):
    future = model.make_future_dataframe(periods=periods)
    forecast = model.predict(future)
    forecast['yhat'] = forecast['yhat'].clip(lower=0)
    forecast['yhat_lower'] = forecast['yhat_lower'].clip(lower=0)
    forecast['yhat_upper'] = forecast['yhat_upper'].clip(lower=0)
    return forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']]


@require_http_methods(["GET"])
def daily_assess(request):
    file_path = '每日进出港统计.xlsx'
    df = load_data(file_path)

    # 初始化Prophet模型，并设置参数
    model = Prophet(
        seasonality_mode='multiplicative',
        seasonality_prior_scale=0.5,
        changepoint_prior_scale=0.01,
        n_changepoints=20,
        interval_width=0.65
    )


    # 训练模型
    model.fit(df)

    # 进行交叉验证
    try:
        df_cv = cross_validation(
            model,
            initial='400 days',
            period='14 days',
            horizon='14 days'
        )
    except ValueError as e:
        print(e)
        print("Please adjust the parameters and try again.")
        return JsonResponse({"error": "Error during cross validation"}, status=500)

    # 计算性能指标
    df_p = performance_metrics(df_cv)

    # 预测未来日期
    forecast = predict(model, periods=14)

    # 只保留最后28条记录
    forecast_last_28 = forecast.tail(28)

    # 将DataFrame转换为适合ECharts的数据格式
    data = forecast_last_28.to_dict(orient='records')
    formatted_data = [
        {
            'date': row['ds'].strftime('%Y-%m-%d'),  # 只包含日期部分
            'value': row['yhat'],
            'l': row['yhat_lower'],
            'u': row['yhat_upper']
        }
        for row in data
    ]

    return JsonResponse(formatted_data, safe=False, json_dumps_params={'ensure_ascii': False})


@require_http_methods(["GET"])
def getdaily(request):
    # 从Redis中获取数据
    data = redis_client.get('daily_data')
    if data:
        formatted_data = json.loads(data)
    else:
        # 如果Redis中没有数据，则调用setdaily方法生成数据并存储到Redis中
        setdaily(request)  # 修改: 传递request参数
        formatted_data = json.loads(redis_client.get('daily_data'))
    return JsonResponse(formatted_data, safe=False, json_dumps_params={'ensure_ascii': False})


@require_http_methods(["GET"])
def setdaily(request):
    # 调用setdaily方法来生成并存储数据
    df = load_data('每日进出港统计.xlsx')
    model = train_model(df)
    forecast = predict(model)

    # 只保留最后28条记录
    forecast_last_28 = forecast.tail(28)

    # 将DataFrame转换为适合ECharts的数据格式
    data = forecast_last_28.to_dict(orient='records')
    formatted_data = [
        {
            'date': row['ds'].strftime('%Y-%m-%d'),  # 只包含日期部分
            'value': row['yhat'],
            'l': row['yhat_lower'],
            'u': row['yhat_upper']
        }
        for row in data
    ]

    # 将数据存储到Redis中
    redis_client.set('daily_data', json.dumps(formatted_data))
    return JsonResponse("每日预测内容生成成功", safe=False, json_dumps_params={'ensure_ascii': False})